package de.codi.mappingevaluation;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.codi.exception.CodiException;
import de.unima.alcomox.exceptions.MappingException;
import de.unima.alcomox.mapping.Correspondence;
import de.unima.alcomox.mapping.Mapping;


public class MappingEvaluation
{

    private static String outputPath = "res/codi-2012-02-21.html";


    public static void main(String[] args) throws CodiException, MappingException
    {
        Mapping ref;
        // ref = new Mapping("res/anatomy/reference_2010_xyz.rdf");
        ref = new Mapping("res/anatomy/reference_2011.rdf");
        List<MappingPlus> mapping = new ArrayList<MappingPlus>();

        mapping.add(new MappingPlus(new File("res/anatomy/reference_2011.rdf"), "Reference 2011"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/top5-2010-correct-ref2011.rdf"), "2010-Top5-Correct-2011"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-beforeRockit07-62.rdf"), "before RockIt-0,7-v6.2"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-afterRockit07-62.rdf"), "after RockIt-0,7-v6.2"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-beforeRockit07-7.rdf"), "before RockIt-0,7-v7"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-afterRockit07-7.rdf"), "after RockIt-0,7-v7"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-beforeRockit07-72.rdf"), "before RockIt-0,7-v7.2"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-afterRockit07-72.rdf"), "after RockIt-0,7-v7.2"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-beforeRockit07-73.rdf"), "before RockIt-0,7-v7.3"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-afterRockit07-73.rdf"), "after RockIt-0,7-v7.3"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-beforeRockit07-81.rdf"), "before RockIt-0,7-v8.1"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-teilmengen-afterRockit07-81.rdf"), "after RockIt-0,7-v8.1"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-2012021-before-v1.rdf"), "20120221 v1 before"));
        mapping.add(new MappingPlus(new File("res/anatomymapping/mapping-2012021-after-v1.rdf"), "20120221 v1 after"));

        // mapping.add(new MappingPlus(new File("res/anatomymapping/cosine-before.rdf"), "before cosine"));
        // mapping.add(new MappingPlus(new File("res/anatomymapping/cosine-after.rdf"), "after cosine"));

        /*
         * // OAEI 2010 (sorted): mapping.add(new MappingPlus(new
         * File("res/anatomy/reference_2010_xyz.rdf"), "Reference 2010"));
         * mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/AgrMaker.rdf"), "AgrMaker"));
         * mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/Ef2Match.rdf"), "Ef2Match"));
         * mapping.add(new MappingPlus(new File("res/anatomy/task-1/NBJLM.rdf"),
         * "NBJLM")); mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/SOBOM.rdf"), "SOBOM")); mapping.add(new
         * MappingPlus(new File("res/anatomy/task-1/BLOOMS.rdf"), "BLOOMS")); //
         * mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/SOBOM_bad.rdf"), "SOBOM_bad"));
         * mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/TaxoMap.rdf"), "TaxoMap")); mapping.add(new
         * MappingPlus(new File("res/anatomy/task-1/ASMOV.rdf"), "ASMOV"));
         * mapping.add(new MappingPlus(new File("res/anatomy/task-1/CODI.rdf"),
         * "CODI")); mapping.add(new MappingPlus(new
         * File("res/anatomy/task-1/GeRMeSMB.rdf"), "GeRMeSMB"));
         * mapping.add(new MappingPlus(new File("res/anatomy/task-1/Aroma.rdf"),
         * "Aroma"));
         */

        String sourcePath = new File("res/anatomy/mouse_anatomy_2010.owl").toURI().toString();
        String targetPath = new File("res/anatomy/nci_anatomy_2010.owl").toURI().toString();
        ReadOntology source = new ReadOntology(sourcePath);
        ReadOntology target = new ReadOntology(targetPath);
        Map<String, Set<String>> infoS = source.info;
        Map<String, Set<String>> infoT = target.info;
        new MappingEvaluation(infoS, infoT, ref, mapping);
    }


    public MappingEvaluation(Map<String, Set<String>> infoS, Map<String, Set<String>> infoT, Mapping reference, List<MappingPlus> mapping)
    {
        // Map: c -> cp
        Map<Correspondence, CorrespondencePlus> cMap = new HashMap<Correspondence, CorrespondencePlus>();
        // Map: cp -> String[]
        Map<CorrespondencePlus, String[]> cpMap = new HashMap<CorrespondencePlus, String[]>();

        // cp for Ref-Mapping
        for(Correspondence c : reference) {
            CorrespondencePlus cp1 = new CorrespondencePlus(c, infoS.get(c.getSourceEntityUri()), infoT.get(c.getTargetEntityUri()), true);
            cpMap.put(cp1, getStringArray(mapping.size()));
            cMap.put(c, cp1);
        }
        int index = 0;

        // for every mapping-File:
        for(MappingPlus mp : mapping) {
            index++;
            mp.setCharacteristic(reference);
            // generate cp for all correspendence
            for(Correspondence c : mp.getMapping()) {
                CorrespondencePlus cp;

                if(!cMap.keySet().contains(c)) {
                    Set<String> sS = infoS.get(c.getSourceEntityUri());
                    Set<String> sT = infoT.get(c.getTargetEntityUri());

                    // no info (why?)
                    if(sS == null) {
                        System.out.println(c.getSourceEntityUri() + "<- " + c.getTargetEntityUri());
                        sS = new HashSet<String>();

                    }
                    if(sT == null) {
                        System.out.println(c.getSourceEntityUri() + " ->" + c.getTargetEntityUri());
                        sT = new HashSet<String>();
                    }

                    cp = new CorrespondencePlus(c, sS, sT, false);
                    cMap.put(c, cp);
                    cpMap.put(cp, getStringArray(mapping.size()));

                } else {
                    cp = cMap.get(c);
                }

                // mark matched
                String[] values = cpMap.get(cp);
                values[index - 1] = "x";
                cp.incCount();
            }
        }

        // sort - cp
        List<CorrespondencePlus> cpList = new ArrayList<CorrespondencePlus>(cpMap.keySet());
        Collections.sort(cpList);
        // toHTML...
        saveToFile(toHTML(cpList, cpMap, mapping));
    }


    private void saveToFile(String htmlString)
    {
        File file = new File(outputPath);
        try {
            file.createNewFile();
            BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF8"));
            fw.write(htmlString);
            fw.flush();
            fw.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }


    private String[] getStringArray(int n)
    {
        String[] temp = new String[n];
        for(int i = 0; i < temp.length; i++) {
            temp[i] = "-";
        }
        return temp;
    }


    private String getString(String[] temp, List<MappingPlus> mpList)
    {
        String s = "";
        for(int i = 0; i < temp.length; i++) {
            if(temp[i].equalsIgnoreCase("x")) {
                if(!s.equals("")) {
                    s += ", ";
                }
                s += "<a href=\"#" + (i + 1) + "\">" + mpList.get(i).getDescription() + "[" + (i + 1) + "]" + "</a>";
            }

        }
        return s;
    }


    private String getTableRow(CorrespondencePlus cp, String[] result, String[] desc)
    {
        String htmlClassCorrect;
        if(cp.isCorrect()) {
            htmlClassCorrect = "correct";
        } else {
            htmlClassCorrect = "wrong";
        }
        String htmlClassClear;
        if(cp.isClear()) {
            htmlClassClear = " class=\"clear\"";
        } else {
            htmlClassClear = "";
        }

        String matcherRes = "res";

        String s = "<tr><td" + htmlClassClear + "><a href=\"#" + cp.getID() + "\" class=\"" + htmlClassCorrect + "\">" + cp.getID() + "</a></td>";
        s += "<td class=\"" + matcherRes + "\">" + cp.getCount() + "</td>";
        for(int i = 0; i < result.length; i++) {
            s += "<td class=\"" + matcherRes + "\"><span title=\"" + desc[i] + " \">" + result[i] + "</span></td>";
        }
        s += "</tr>";
        return s;
    }


    private String toHTML(List<CorrespondencePlus> cpList, Map<CorrespondencePlus, String[]> cpMap, List<MappingPlus> mpList)
    {
        StringBuffer sb = new StringBuffer();
        StringBuffer moreDetails = new StringBuffer();
        String[] desc = new String[mpList.size()];
        sb.append(getHTMLHeader());
        sb.append("<h1 id=\"head\">Mapping Result</h1>");
        sb.append("<table><tr>");
        sb.append("<th>Mapping</th><th>N</th>");
        for(int i = 0; i < mpList.size(); i++) {
            sb.append("<th><a href=\"#" + (i + 1) + "\">" + (i + 1) + "</a></th>");
            desc[i] = mpList.get(i).getDescription();
        }
        sb.append("</tr>");
        for(CorrespondencePlus cp : cpList) {
            String[] row = cpMap.get(cp);
            // eindeutige,clear, nicht gefundene, unm�gliche streichen
            if((cp.getCount() > 0) && (cp.getCount() / row.length) != 1 /* && !cp.isClear() && !skip.contains(cp.getID()) */) {
                sb.append(getTableRow(cp, row, desc));
                moreDetails.append(cp.getHTML(getString(row, mpList)));
            }
        }
        sb.append("</table>");

        // mapping info
        String top = "&#09;" + "<a href=\"#head\">" + "[top]" + "</a>";
        for(int i = 0; i < mpList.size(); i++) {
            MappingPlus mp = mpList.get(i);
            sb.append("<div id=\"" + (i + 1) + "\">");
            sb.append("<h2>" + (i + 1) + " - " + mp.getDescription() + top + "</h2>");
            sb.append("<p>" + mp.getResult().replaceAll("\n", "<br/>") + "<br/></p>");
            sb.append("</div>");
        }

        sb.append(moreDetails);
        sb.append(getHTMLFooter());
        return sb.toString();
    }


    private String getHTMLHeader()
    {
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
        sb.append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
        sb.append("<head>");
        sb.append("<title>Mapping - Results</title>");
        sb.append("<link rel=\"stylesheet\" media=\"screen\" href=\"style.css\">");
        sb.append("</head>");
        sb.append("<body>");
        return sb.toString();
    }


    private String getHTMLFooter()
    {
        StringBuffer sb = new StringBuffer();
        sb.append("</body></html>");
        return sb.toString();
    }
}
